<?php
/**
 * 测试用例 运行类
 *
 * @author KenXu
 * @date: 2010-7-28 下午01:48:57
 */
class Kenxu_Unit_Runner {
	
	/**
	 * 测试用例对象
	 * @var Kenxu_Unit_TestCase $_testCase
	 */
	private $_testCase = null ;
	
	/**
	 * 测试用例对象的反射
	 * @var ReflectionClass $_reflect
	 */
	private $_reflect = null ;
	
	/**
	 * 测试结果
	 * @var array
	 */
	private $_result = null ;
	
	public function execute(Kenxu_Unit_TestCase $testCase){
		
		$this->_testCase = $testCase ;
		
		$this->_reflect = new ReflectionClass($testCase);
		
		// 向 结果集中注入类的名称
		$this->_result = array(
			'class' => $this->_reflect->getName() ,
			'file' =>  $this->_reflect->getFileName()
		);		
		
		// 获取 测试用例运行前断言的执行次数
		$start = Kenxu_Unit_Assert::getCount();
		
		// 测试用例运行时如果抛出异常 则终止这个测试用例,并且此时不包含测试信息		
		try {
			
			// 此处加上 基准测试的 起点
			
			$this->_testCase->setUp();
			
			// 执行测试方法
			$testMethods = $this->_fetchTestMethods($this->_testCase);
			
			if (!empty($testMethods)){
				
				$this->_result['failed'] = 0 ;
				
				$this->_result['methods'] = array() ;
				
				foreach ($testMethods as $testMethod) {
					$this->_evaluate($testMethod);
					
					$this->_result['failed'] += $this->_result['methods'][$testMethod]['failed'] ;
				}
				
			}
			
			$this->_testCase->tearDown();
			
			// 此处加上 基准测试的 终结
			
			// 获取 测试用例执行完成后断言的执行次数
			$stop = Kenxu_Unit_Assert::getCount();
			
			$total = $stop - $start ;
			
			$this->_result['total'] = $total ;
			$this->_result['success'] = $total - $this->_result['failed'] ;
			
			
		} catch (Exception $ex){			
			$this->_result['bug'] = $ex->getMessage() ;
			$this->_result['bug_trace'] = $ex->getTraceAsString() ;			
		}
		
		return $this->_result ;
	}
	
	/**
	 * 执行方法
	 * @param string $testMethod
	 */
	private function _evaluate($testMethod){
		// 获取 当前测试方法运行前断言的执行次数
		$start = Kenxu_Unit_Assert::getCount();
		
		$this->_testCase->{$testMethod}();
		
		// 获取  当前测试方法执行完成后断言的执行次数
		$stop = Kenxu_Unit_Assert::getCount();
		
		$total = $stop - $start ;
		
		// 获取方法 对应的 断言失败时 的错误信息集合
		$assertFaileds = Kenxu_Unit_Assert::getAssertionFailedTrace($this->_result['class'],$testMethod) ;
		$this->_result['methods'][$testMethod] = array(
			'total' => $total ,
			'success' => $total - count($assertFaileds) ,
			'failed' => count($assertFaileds) ,
			'asserts' => $assertFaileds
		) ; 
	}
	
	/**
	 * 获取测试用例对象的Test方法集合: 方法以Test结尾,缺省不区分大小写
	 * 
	 * @param Kenxu_Unit_TestCase $testCase
	 * @param bool $noCaseSensitiveClassMethods 方法名称是否区分大小写
	 * @return array
	 */
	private function _fetchTestMethods(Kenxu_Unit_TestCase $testCase ,$noCaseSensitive = true){
		// PHP5 开始 返回的方法名称 区分 大小写
		$methods = get_class_methods($testCase); 
		// array_map('strtolower', $methods);
		$testMethods = array();
		
		$identifier = $noCaseSensitive ? '/Test$/i' : '/Test$/' ;
		
		foreach ($methods as $method) {
			if (preg_match($identifier,$method) && is_callable(array($testCase,$method))){
				$testMethods[] = $method ;
			}
		}
		return $testMethods ;
	}
	
}